我們上回已經完成Instagram的首頁區塊了,接下來我們要繼續打造新的區塊,這次要編寫的是建立新貼文的區塊,也就是按下側邊欄的Create按鈕時會出現的區塊,雖然真實的Instagram能在建立貼文時裁切和套用濾鏡,但是我們的專案會省略這些部分,專注於發佈新貼文的部分。
我們在Post資料夾底下,新增CreatePostModal.jsx,是建立新貼文部分的主體,按下Create按鈕會彈出的視窗,內容有一部分是之前複製過的Chakra UI範例。
import {
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
} from "@chakra-ui/react";
import React from "react";
const CreatePostModal = ({ onClose, isOpen }) => {
return (
<div>
<Modal size={"4xl"} onClose={onClose} isOpen={true} isCentered>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody></ModalBody>
</ModalContent>
</Modal>
</div>
);
};
export default CreatePostModal;
來到HomePage.jsx,在最後的部分加上。
import React from 'react'
import StoryCircle from "../../Components/Story/StoryCircle"
import HomeRight from "../../Components/HomeRight/HomeRight"
import PostCard from "../../Components/Post/PostCard"
import CreatePostModal from "../../Components/Post/CreatePostModal"
const HomePage = () => {
return (
<div>
<div className="mt-10 flex w-[100%] justify-center">
<div className="w-[44%] px-10">
<div className="flex space-x-2 border p-4 rounded-md justify-start w-full">
{
[1, 1, 1].map((item) => (
<StoryCircle />
))
}
</div>
<div className="space-y-10 w-full mt-10">
{[1, 1].map((item) => <PostCard />)}
</div>
</div>
<div className="w-[35%]">
<HomeRight />
</div>
</div>
<CreatePostModal />
</div>
)
}
export default HomePage
確認一下,程式有沒有正常運作,要是啪的一下子寫一堆程式碼,最後才發現不能正常顯示就不好了。
我們開始編寫部分排版,修改CreatePostModal.jsx。
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalOverlay,
} from "@chakra-ui/react";
import React from "react";
const CreatePostModal = ({ onClose, isOpen }) => {
return (
<div>
<Modal size={"4xl"} onClose={onClose} isOpen={true} isCentered>
<ModalOverlay />
<ModalContent>
<div className="flex justify-between py-1 px-10 items-center">
<p>Create New Post</p>
<Button variant={"ghost"} size="sm" colorScheme={"blue"}>
Share
</Button>
</div>
<ModalBody></ModalBody>
</ModalContent>
</Modal>
</div>
);
};
export default CreatePostModal;
修改CreatePostModal.jsx,繼續顯示出上傳圖片或影片的文字。
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalOverlay,
} from "@chakra-ui/react";
import React from "react";
import { FaPhotoVideo } from "react-icons/fa";
const CreatePostModal = ({ onClose, isOpen }) => {
return (
<div>
<Modal size={"4xl"} onClose={onClose} isOpen={true} isCentered>
<ModalOverlay />
<ModalContent>
<div className="flex justify-between py-1 px-10 items-center">
<p>Create New Post</p>
<Button variant={"ghost"} size="sm" colorScheme={"blue"}>
Share
</Button>
</div>
<hr />
<ModalBody>
<div>
<div>
<div>
<div>
<FaPhotoVideo className="text-3xl" />
<p>Drag photos and videos here</p>
</div>
</div>
</div>
</div>
</ModalBody>
</ModalContent>
</Modal>
</div>
);
};
export default CreatePostModal;
接下來,我們處理上傳的部分,先寫出大概的外觀,實際上傳的部分以後再說,將CreatePostModal.jsx修改成以下內容:
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalOverlay,
} from "@chakra-ui/react";
import React, { useState } from "react";
import { FaPhotoVideo } from "react-icons/fa";
import './CreatePostModal.css';
const CreatePostModal = ({ onClose, isOpen }) => {
const [isDragOver, setIsDragOver] = useState(false);
const [file, setFile] = useState();
const handleDrop = (e) => {
e.preventDefault();
const droppedFile = e.dataTransfer.file[0];
//檢查檔案類型是圖片或影片才能上傳
if (
droppedFile.type.startsWith("image/") ||
droppedFile.type.startsWith("video/")
) {
setFile(droppedFile);
}
};
const handleDragOver = (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = "copy";
setIsDragOver(true);
};
const handleDragLeave = () => {
setIsDragOver(false);
};
//上傳檔案時,確認是不是圖片或影片
const handleOnChange = (e) => {
const file = e.target.file[0];
if (
file &&
(file.type.startsWith("image/") || file.type.startsWith("video/"))
) {
setFile(file);
} else {
setFile(null);
alert("Please upload an image or video");
}
};
return (
<div>
<Modal size={"4xl"} onClose={onClose} isOpen={true} isCentered>
<ModalOverlay />
<ModalContent>
<div className="flex justify-between py-1 px-10 items-center">
<p>Create New Post</p>
<Button variant={"ghost"} size="sm" colorScheme={"blue"}>
Share
</Button>
</div>
<hr />
<ModalBody>
<div>
<div className="w-[50%]">
<div
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
className="drag-drop h-full"
>
<div>
<FaPhotoVideo className="text-3xl" />
<p>Drag photos and videos here</p>
</div>
<label htmlFor="file-upload" className="custom-file-upload">
Select From Computer
</label>
<input
className="file-input"
type="file"
id="file-upload"
accept="image/*, video/*"
onChange={handleOnChange}
/>
</div>
</div>
</div>
</ModalBody>
</ModalContent>
</Modal>
</div>
);
};
export default CreatePostModal;
isDragOver代表是否有內容拖曳到網頁中。
handleDrop的作用是當檔案拖曳進來時,確認檔案類型,如果符合,就設定成上傳的檔案。
handleDragOver有檔案拖動到網頁上就會做裏面的內容。
handleDragLeave將檔案移動到網頁上後又離開,就會執行裏面的程式碼。
handleOnChange按下按鈕上傳檔案時會進行裏面的動作。
在Post資料夾底下,新增CreatePostModal.css。
.drag-drop{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 2rem;
font-size: 1.2rem;
color: #999;
border-radius: 5px;
cursor: pointer;
}
.drag-drop p{
margin: 0 0 1rem;
}
.custom-file-upload{
padding: .5rem 1rem;
font-weight: 600;
color: white;
background-color: #0095F6;
border: 1px solid #0095F6;
cursor: pointer;
}
.custom-file-upload:hover{
background-color: #1877F2;
border-color: #1877F2;
}
input[type="file"]{
display: none;
}
.fileInput{
display: none;
}
完成後的外觀是這樣,可以拖曳檔案到這個地方,也可以按下藍色的按鈕上傳內容,雖然什麼也不會發生,因為我們沒寫實際的上傳處理。